package com.xxmw.transaction.task;

import com.xxmw.transaction.common.utils.bourse.BitforexUtil;
import com.xxmw.transaction.common.utils.bourse.OkexUtil;
import com.xxmw.transaction.controller.server.TransactionWebsocketServer;
import com.xxmw.transaction.enumeration.TopicEnum;
import com.xxmw.transaction.enumeration.TradeTypeEnum;
import com.xxmw.transaction.model.app.BourseApi;
import com.xxmw.transaction.model.app.BourseOrder;
import com.xxmw.transaction.model.robot.RobotOrder;
import com.xxmw.transaction.service.app.BourseApiService;
import com.xxmw.transaction.service.robot.RobotOrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 机器人挂单定时任务
 * @author luowenliang
 * @since 2020/2/20 08:43
 */
@Slf4j
@Component("robotOrderTask")
public class RobotOrderTask {

    private static String JOBTIMES = ":jobtimes";

    private static final SimpleDateFormat DF = new SimpleDateFormat("HH:mm:ss");

    @Autowired
    private RobotOrderService robotOrderService;

    @Autowired
    private BourseApiService bourseApiService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 自动挂单任务
     * 该定时任务15秒执行一次 一分钟4次 随机取一次吃单
     * @param param 1,btc...
     */
    public void place (String param) {
        try {
            String[] params = param.split(",");
            Integer bourse = Integer.valueOf(params[0]);
            String symbol = params[1];
            log.info("机器人挂单定时任务执行，参数【交易所：{},交易对：{}】", bourse, symbol);
            int times = orderTimesIncrAndGet(bourse, symbol);
            robotOrderService.volumeOrder(bourse, symbol, times);
            if (4 <= times) {
                orderTimesReset(bourse, symbol);
            }
        } catch (Exception e) {
            log.error("机器人挂单定时任务执行异常", e);
        }
    }

    private int orderTimesIncrAndGet (Integer bourse, String symbol) {
        String key = bourse + ":" + symbol + JOBTIMES;
        Long increment = redisTemplate.opsForValue().increment(key);
        return increment.intValue();
    }

    private void orderTimesReset (Integer bourse, String symbol) {
        String key = bourse + ":" + symbol + JOBTIMES;
        redisTemplate.opsForValue().set(key, "0");
    }

    /**
     * 交易所订单撤销任务
     */
    public void cancel () {
        List<RobotOrder> orderList = robotOrderService.getOrderByStatus(1, 3);
        if (null != orderList && orderList.size() > 0) {
            HashMap<Integer, BourseApi> apiMap = bourseApiService.list().stream().collect(HashMap::new, (map, api) -> map.put(api.getBourse(), api), Map::putAll);
            for (RobotOrder order : orderList) {
                boolean isBuy = order.getTradeType().equals(TradeTypeEnum.BUY_LIMIT.getValue());
                switch (order.getBourse()) {
                    case 1:
                        //TODO 火币
                        break;
                    case 2:
                        //TODO 币安
                        break;
                    case 3:
                        //TODO Okex
                        OkexUtil.cancelOrder(apiMap.get(3), order);
                        break;
                    case 4:
                        //TODO BitForex
                        if (robotOrderService.needCancel(4, order.getSymbol(), isBuy)) {
                            BitforexUtil.cancelOrder(apiMap.get(4), order);
//                            CompletableFuture.runAsync(() -> robotOrderService.clearRecentlyOrder(4, order.getSymbol(), isBuy));
                        }
                        break;
                    default:
                        log.error("存在未知的交易所订单：{}", order.getBourse());
                }
                //状态变了才去更新订单
                if (BourseOrder.Status.CANCELING.equals(order.getStatus()) || BourseOrder.Status.CANCLED.equals(order.getStatus())) {
                    robotOrderService.updateById(order);
                }
            }
        }
    }

    /**
     * 订单状态更新
     * 查询所有已提交的订单，到交易所去查询订单状态，并做更新
     */
    public void orderStatusUpdate () {
        List<RobotOrder> orderList = robotOrderService.getOrderByStatus(1, 2, 3);
        if (null != orderList && orderList.size() > 0) {
            HashMap<Integer, BourseApi> apiMap = bourseApiService.list().stream().collect(HashMap::new, (map, api) -> map.put(api.getBourse(), api), Map::putAll);
            for (RobotOrder order : orderList) {
                int expected = order.getStatus();
                switch (order.getBourse()) {
                    case 1:
//                        HuobiUtil.orderInfo();
                        break;
                    case 2:
                        //TODO 币安
                        break;
                    case 3:
                        //TODO Okex
                        OkexUtil.orderInfo(apiMap.get(3), order);
                        break;
                    case 4:
                        //TODO BitForex
                        BitforexUtil.orderInfo(apiMap.get(4), order);
                        break;
                    default:
                        log.error("存在未知的交易所订单：{}", order.getBourse());
                }
                if (expected != order.getStatus()) {
                    //状态变了才去更新订单
                    int u = robotOrderService.updateByIdAndExpected(order, expected);
                    if (u > 0 && order.getDealNum().compareTo(BigDecimal.ZERO) == 1 && null != order.getDealTime()) {
                        //如有订单成交更新成交量
                        log.info("更新订单成功,该笔订单成交量num：{}", order.getDealNum());
                        robotOrderService.volumeSet(order.getBourse(), order.getSymbol(), order.getDealNum());
                        //推送消息
                        CompletableFuture.runAsync(() -> pushedSymbolDealInfo(order));
                    }
                }
            }
        }
    }

    /**
     * 推送ctc成交信息
     * @param order
     */
    private void pushedSymbolDealInfo (RobotOrder order) {
        String symbol = order.getSymbol();
        Map<String, Object> map = new HashMap<>();
        map.put("dealTime", DF.format(order.getDealTime()));
        map.put("dealNum", order.getDealNum());
        map.put("price", order.getAvgPrice());
        log.info("推送CTC成交信息【symbol:{}, dealNum:{}, dealTime:{}】", symbol, order.getDealNum(), order.getDealTime());
        ConcurrentHashMap<Long, TransactionWebsocketServer> serverMap = TransactionWebsocketServer.getServer();
        if (!serverMap.isEmpty()) {
            serverMap.forEach((id, server) -> {
                if (symbol.equals("ctceth")) {
                    if (server.isSubscribed(TopicEnum.CTCETH_DEAL_TOPIC.getDesc())) {
                        server.senObject(map);
                    }
                } else if (symbol.equals("ctcusdt")) {
                    if (server.isSubscribed(TopicEnum.CTCUSDT_DEAL_TOPIC.getDesc())) {
                        server.senObject(map);
                    }
                }
            });
        }
    }
}
